package de.bk.timecalc.console;

import static de.bk.timecalc.i18n.I18nKeys.UNPARSEABLE_TIME;
import static de.bk.timecalc.i18n.I18nKeys.UNPARSEABLE_TIME_EMPTY_STRING_OR_ONLY_WHITESPACE;
import static de.bk.timecalc.i18n.I18nKeys.UNPARSEABLE_TIME_MINUTE_TOO_BIG;
import static de.bk.timecalc.i18n.I18nKeys.UNPARSEABLE_TIME_NON_NUMERIC_CHARACTER;
import static de.bk.timecalc.i18n.I18nKeys.UNPARSEABLE_TIME_NOT_ENOUGH_DIGITS;
import static de.bk.timecalc.i18n.I18nKeys.UNPARSEABLE_TIME_NO_MINUTES;
import static de.bk.timecalc.i18n.I18nKeys.UNPARSEABLE_TIME_NO_MINUTES_AND_NO_SECONDS;
import static de.bk.timecalc.i18n.I18nKeys.UNPARSEABLE_TIME_NO_SECONDS;
import static de.bk.timecalc.i18n.I18nKeys.UNPARSEABLE_TIME_SECOND_TOO_BIG;
import static de.bk.timecalc.i18n.I18nKeys.UNPARSEABLE_TIME_TOO_MANY_COLONS;
import static de.bk.timecalc.i18n.I18nKeys.UNPARSEABLE_TIME_TOO_MANY_DIGITS;
import static de.bk.timecalc.i18n.I18nKeys.UNPARSEABLE_TIME_TOO_MANY_DIGITS_AFTER_COLON;
import static de.bk.timecalc.i18n.I18nKeys.UNPARSEABLE_TIME_TOO_MANY_DIGITS_BEFORE_COLON;
import de.bk.timecalc.core.TimeDTO;
import de.bk.timecalc.i18n.StringFactory;

/**
 * @author Bastian Krol
 * @version $Revision:$ $Date:$ $Author:$
 */
public class LineParser
{

  public TimeDTO parse(String string) throws LineNotParseableException
  {
    if (string == null)
    {
      throw new IllegalArgumentException("string may not be null");
    }
    string = string.trim();
    if (string.length() == 0)
    {
      throw new LineNotParseableException(this.getString(UNPARSEABLE_TIME)
          + this.getString(UNPARSEABLE_TIME_EMPTY_STRING_OR_ONLY_WHITESPACE));
    }
    if (string.contains(":"))
    {
      String[] parts = string.split(":");
      if (parts.length > 2)
      {
        throw new LineNotParseableException(this.getString(UNPARSEABLE_TIME)
            + this.getString(UNPARSEABLE_TIME_TOO_MANY_COLONS));
      }
      else if (parts.length == 1)
      {
        throw new LineNotParseableException(this.getString(UNPARSEABLE_TIME)
            + this.getString(UNPARSEABLE_TIME_NO_SECONDS));
      }
      else if (parts.length == 0)
      {
        throw new LineNotParseableException(this.getString(UNPARSEABLE_TIME)
            + this.getString(UNPARSEABLE_TIME_NO_MINUTES_AND_NO_SECONDS));
      }
      String minutesString = parts[0].trim();
      String secondsString = parts[1].trim();
      if (minutesString.equals(""))
      {
        throw new LineNotParseableException(this.getString(UNPARSEABLE_TIME)
            + this.getString(UNPARSEABLE_TIME_NO_MINUTES));
      }
      else if (minutesString.length() > 2)
      {
        throw new LineNotParseableException(this.getString(UNPARSEABLE_TIME)
            + this.getString(UNPARSEABLE_TIME_TOO_MANY_DIGITS_BEFORE_COLON));
      }
      else if (secondsString.length() > 2)
      {
        throw new LineNotParseableException(this.getString(UNPARSEABLE_TIME)
            + this.getString(UNPARSEABLE_TIME_TOO_MANY_DIGITS_AFTER_COLON));
      }
      this.checkNumeric(minutesString);
      this.checkNumeric(secondsString);
      return createTimeDTO(Integer.parseInt(minutesString), Integer
          .parseInt(secondsString));
    }

    this.checkNumeric(string);
    if (string.length() == 4)
    {
      return createTimeDTO(Integer.parseInt(string.substring(0, 2)), Integer
          .parseInt(string.substring(2, 4)));
    }
    else if (string.length() == 3)
    {
      return createTimeDTO(Integer.parseInt(string.substring(0, 1)), Integer
          .parseInt(string.substring(1, 3)));
    }
    else if (string.length() == 2)
    {
      return createTimeDTO(Integer.parseInt(string.substring(0, 1)), Integer
          .parseInt(string.substring(1, 2)));
    }
    else if (string.length() == 1)
    {
      throw new LineNotParseableException(this.getString(UNPARSEABLE_TIME)
          + this.getString(UNPARSEABLE_TIME_NOT_ENOUGH_DIGITS));
    }
    else if (string.length() > 4)
    {
      throw new LineNotParseableException(this.getString(UNPARSEABLE_TIME)
          + this.getString(UNPARSEABLE_TIME_TOO_MANY_DIGITS));
    }
    return null;
  }

  private void checkNumeric(String string) throws LineNotParseableException
  {
    for (char c : string.toCharArray())
    {
      if (!Character.isDigit(c))
      {
        throw new LineNotParseableException(this.getString(UNPARSEABLE_TIME)
            + StringFactory.getInstance().format(
                UNPARSEABLE_TIME_NON_NUMERIC_CHARACTER, c));
      }
    }
  }

  private TimeDTO createTimeDTO(int minute, int second)
      throws LineNotParseableException
  {
    if (minute > 59)
    {
      throw new LineNotParseableException(this.getString(UNPARSEABLE_TIME)
          + this.getString(UNPARSEABLE_TIME_MINUTE_TOO_BIG));
    }
    else if (second > 59)
    {
      throw new LineNotParseableException(this.getString(UNPARSEABLE_TIME)
          + this.getString(UNPARSEABLE_TIME_SECOND_TOO_BIG));
    }
    return new TimeDTO(minute, second);
  }

  private String getString(String key)
  {
    return StringFactory.getInstance().getString(key);
  }
}
